#include<iostream>
#include<limits.h>
#include<string.h>

using namespace std;

//Wrapper class for storing a graph
class Graph{
	public:
	int vertexNum;
	int** edges;

	//Constructs a graph with V vertices and E edges
	Graph(int V){
		this->vertexNum = V;
		this->edges =(int**) malloc(V * sizeof(int*));
		for(int i=0; i<V; i++){
			this->edges[i] = (int*) malloc(V * sizeof(int));
			for(int j=0; j<V; j++)
				this->edges[i][j] = INT_MAX;
			this->edges[i][i] = 0;
		}		
	}

	//Adds the given edge to the graph 
	void addEdge(int src, int dst, int weight){
		this->edges[src][dst] = weight;
	}
	

};


//Utility function to print distances
void print(int dist[], int V){
	cout<<"\nThe Distance matrix for Floyd - Warshall"<<endl;
	for(int i = 0; i < V; i++){
		for(int j=0; j<V; j++){

		if(dist[i*V+j] != INT_MAX)	
			cout<<dist[i*V+j]<<"\t";
		else
			cout<<"INF"<<"\t";
		}
		cout<<endl;
	}
}

//The main function that finds the shortest path from a vertex
//to all other vertices using Floyd-Warshall Algorithm.
void FloydWarshall(Graph graph){
	int V = graph.vertexNum;
	int dist[V][V];
	
	//Initialise distance array
	for(int i=0; i<V; i++)
		for(int j=0; j<V; j++)
			dist[i][j] = graph.edges[i][j];	
			
	
	//Calculate distances
	for(int k=0; k<V; k++)
	//Choose an intermediate vertex

		for(int i=0; i<V; i++)	
		//Choose a source vertex for given intermediate

			for(int j=0; j<V; j++)
			//Choose a destination vertex for above source vertex

				if(dist[i][k] != INT_MAX && dist[k][j] != INT_MAX && dist[i][k] + dist[k][j] < dist[i][j])
				//If the distance through intermediate vertex is less than direct edge then update value in distance array
					dist[i][j] = dist[i][k] + dist[k][j];

	
	//Convert 2d array to 1d array for print
	int dist1d[V*V];	
	for(int i=0; i<V; i++)
		for(int j=0; j<V; j++)
			dist1d[i*V+j] = dist[i][j];
	
	print(dist1d,V);	
	}

//Driver Function
int main(){
	int V,E;
	int src,dst,weight;
	cout<<"Enter number of vertices: ";
	cin>>V;
	cout<<"Enter number of edges: ";
	cin>>E;
	Graph G(V);
	for(int i=0; i<E; i++){
		cout<<"\nEdge "<<i+1<<"\nEnter source: ";
		cin>>src;
		cout<<"Enter destination: ";
		cin>>dst;
		cout<<"Enter weight: ";
		cin>>weight;
		G.addEdge(src, dst, weight);
	}
	FloydWarshall(G);

	return 0;
}
